# -*- coding: utf-8 -*-
from captcha.client import submit
from dajaxice.decorators import dajaxice_register
from dajaxice.utils import deserialize_form
from datetime import datetime
from django.contrib.auth.decorators import login_required
from django.core import serializers
from django.core.serializers.json import DjangoJSONEncoder
from django.db.models.signals import post_save
from django.utils import simplejson, timezone
from django.utils.log import logger
from django.utils.translation import ugettext as _
from events.mailhtml import getSucceedTableHtml, sendMail
from events.models import Event, Participant
from users.models import BDAY_LIMIT, UserProfile
from users.views import maskPid
import json
import logging
import random
import settings
import string

@dajaxice_register(method='POST', name='events.eventSignupJSON')
def eventSignupJSON(request, form):
    postdata = deserialize_form(form)
    
    chck_res = check_signup_captcha(request, postdata)
    if not chck_res.is_valid:
        return simplejson.dumps({'result': 'captch_failed' })
    
    event_id = postdata.get('event_id', None)
        
    destEvent = Event.objects.get(pk=event_id)
    if destEvent is None:
        return simplejson.dumps({'result': 'event_id_not_exist' })
    
    # check if participant is existed
    pName = postdata.get('name', None)
    pPid = postdata.get('pid', None)
    
    if destEvent.participant_set.filter(name=pName, pid=pPid).count():
        return simplejson.dumps({'result': 'participant_is_existed' })
    else:
        pBday = postdata.get('bday', None)
        pGender = postdata.get('gender', None)
        pNationality = postdata.get('nationality', None)
        pEmail = postdata.get('email', None)
        pPhoneNum = postdata.get('phoneNum', None)
        pEmgcyContact = postdata.get('emgcyContact', None)
        pEmgcyContPhone = postdata.get('emgcyContPhone', None)
        pEstimateTime = postdata.get('estimateTime', None)

        # check has data
        empty_fields = [];
        if pBday is None: empty_fields.append('bday')
        if pGender is None : empty_fields.append('gender')
        if pNationality is None : empty_fields.append('nationality')
        if pEmail is None : empty_fields.append('email')
        if pPhoneNum is None : empty_fields.append('phoneNum')
        if pEmgcyContact is None : empty_fields.append('emgcyContact')
        if pEmgcyContPhone is None : empty_fields.append('emgcyContPhone')
        if pEstimateTime is None : empty_fields.append('estimateTime')
        if len(empty_fields) > 0:
            return simplejson.dumps({'result':'empty_field', 'empty_field':empty_fields})
        
        # check if year of bday is valid or not
        bdayDT = datetime.strptime(pBday, '%Y-%m-%d')
        td = timezone.now()
        yearsOld = td.year - bdayDT.year
        if yearsOld > BDAY_LIMIT or yearsOld <= 0: return simplejson.dumps({'result': 'invalid_bday' })
        
        post_save.connect(create_signup_key, Participant)
        pdata = Participant.objects.create(event = destEvent,
                                          #user = None,
                                          name = pName,
                                          gender = pGender,
                                          nationality = pNationality,
                                          signupKey = 'default',   # assigned in post_save signal processor
                                          bday = pBday,
                                          pid = pPid,
                                          email = pEmail,
                                          phoneNum = pPhoneNum,
                                          emgcyContact = pEmgcyContact,
                                          emgcyContPhone = pEmgcyContPhone,
                                          estimateTime = pEstimateTime,
                                          signupDateTime = timezone.now(),
                                          )
        sendSuccessEmail(request, pEmail, pdata)
        logging.info('send mail excuted')
        return simplejson.dumps({'result':'succeed' , 'redirect_to':('/events/'+event_id+'/succeed/'+pdata.signupKey + '/')})


def sendSuccessEmail(request, emailAddress, participant):
    logging.info('send mail start excuting')
    '''
    secure = '',
    if HttpRequest.is_secure(request):
        secure = "s"
    '''
    emailSubject = _('5krun event sign-up succeed.')
    
    textBody = _(u'''
                    Dear {username},{NL}
                    Your sign-up of <b>{eventname}</b> is succeed{NL}
                    If any error please using sign-up key to make modification before sign-up is closed.{NL}
                    Sign-up duration: <b>{signupstartDate} ~ {signupendDate}</b>.{NL}
                    Following is your sign-up information:{NL}
                 ''' ).format (
                               NL='<br>',
                               username=participant.name,
                               eventname=participant.event.name,
                               signupstartDate=participant.event.signupStartDateTime,
                               signupendDate=participant.event.signupEndDateTime
                               )
    
    infoTable = getSucceedTableHtml(participant)
    htmlBody = u'''
                    <html>
                        <head></head>
                        <body>
                            <div><p>{textBody}</p></div>
                            <div>{infoTable}</div>
                        </body>
                    </html>  
                 ''' .format (
                              textBody=textBody,
                              infoTable=infoTable
                              )
    try:
        sendMail(subject = emailSubject,
                 fromAddr = settings.DEFAULT_FROM_EMAIL,
                 to_list = [emailAddress],
                 msg_text = '',
                 msg_html = htmlBody)
    except Exception as inst:
        logging.error('Exception when executing sendMail: '+ str(inst))           # __str__ allows args to printed directly
    
    
def create_signup_key(sender, **kwargs):
    kwargs['instance'].signupKey = encodeSignupKey(kwargs['instance'].id)
    post_save.disconnect(receiver=create_signup_key, sender=sender)
    kwargs['instance'].save()
    
      
def check_signup_captcha(request, postdata):
    remote_ip = request.META['REMOTE_ADDR']
    challenge = postdata.get('recaptcha_challenge_field', None)
    response = postdata.get('recaptcha_response_field', None)
    private_key = settings.RECAPTCHA_PRIVATE_KEY
    return submit(challenge, response, private_key, remote_ip)


KEY_LENGTH = 6
def id_generator(chars=string.ascii_uppercase + string.digits):
        return ''.join(random.choice(chars) for x in range(KEY_LENGTH ))

def encodeSignupKey(participantID):
    return id_generator() + str(participantID)

def decodeSignupKey(key):
    return int( key[KEY_LENGTH:] )


@login_required
@dajaxice_register(method='POST', name='events.eventDataExportJSON')
def eventDataExportJSON(request, form):
    logging.info("executing Data export JSON") 
    postdata = deserialize_form(form)
    
    jsonResult = {}
    columns = []
    
    event_id = postdata.get('event_id', None)
    destEvent = Event.objects.get(pk=event_id)
    if destEvent is None:
        jsonResult .update({'result': 'event_id_incorrect' })
        return simplejson.dumps(jsonResult)
    
    # use 2 for loop to make sure event info column is before participant info column
    hasEvent = False
    hasParti = False
    for k in postdata:
        if k=='eventinfoKeys_id':
            hasEvent = True
        elif k == 'participantKeys_id':
            hasParti = True
            
    logging.info('create event info')
    if hasEvent: 
        keys = postdata['eventinfoKeys_id'].split('_')
        for key in keys:
            try:
                attr = getattr(destEvent, key)
                logging.info('get attribute key:{key} from event object'.format(key=key))
            except AttributeError:
                logging.info('wrong attribute key:{key} of event object'.format(key=key))
                continue
            k = 'eventinfo_' + key
            columns.append(k)
            jsonResult.update({k : attr})
    
    logging.info('create participant info')
    if hasParti:
        keys = postdata['participantKeys_id'].split('_')
        pidIndex = -1
        i = 0
        for key in keys:
            if key == 'pid':
                pidIndex = i
            k = 'participant_' + key
            columns.append(k)
            i += 1
    
        logging.info('filter participant column')
        resdict = {}
        reslist = destEvent.participant_set.values_list(*keys)
        
        # if query data has personal id, recreate tuple by list and mask the pid
        if pidIndex >= 0 :
            for idx, items in enumerate(reslist):
                lt = []
                for idT, itemT in enumerate(items):
                    if idT == pidIndex:
                        lt.append(maskPid(str(itemT)))
                    else :
                        lt.append(itemT)
                items = tuple(lt)
                resdict['participant_'+str(idx)] = items
        else:
            for idx, items in enumerate(reslist):
                resdict['participant_'+str(idx)] = items
        
        logging.info('update result dictionary according to participant data')
        jsonResult.update(resdict)
    
    logging.info('update result dictionary according to columns info')
    jsonResult.update({'result':'succeed', 'columns':columns})
    
    return simplejson.dumps(jsonResult, cls=DjangoJSONEncoder); 

@dajaxice_register(method='POST', name='events.eventSignupModifyJSON')
def eventSignupModifyJSON(request, form):
    postdata = deserialize_form(form)
    
    event_id = postdata.get('event_id', None)
        
    destEvent = Event.objects.get(pk=event_id)
    if destEvent is None:
        return simplejson.dumps({'result': 'event_id_not_exist' })
    
    pSignupKey = postdata.get('signupKey', None)
    if pSignupKey is None:
        return simplejson.dumps({'result': 'invalid_signupkey' })
    
    try:
        pdata = Participant.objects.get(signupKey=pSignupKey)
    except (Participant.DoesNotExist, Participant.MultipleObjectsReturned):
        return simplejson.dumps({'result': 'invalid_signupkey' })
    
    pdata.bday = postdata.get('bday', None)
    pdata.gender = postdata.get('gender', None)
    pdata.nationality = postdata.get('nationality', None)
    pdata.email = postdata.get('email', None)
    pdata.phoneNum = postdata.get('phoneNum', None)
    pdata.emgcyContact = postdata.get('emgcyContact', None)
    pdata.emgcyContPhone = postdata.get('emgcyContPhone', None)
    pdata.estimateTime = postdata.get('estimateTime', None)
    try :
        pdata.save()
        # use redirect to refresh the original value (var oriVal={...})  template-coded in the HTML
        return simplejson.dumps({'result':'succeed' , 'redirect_to':('/events/'+event_id+'/signupmodify/'+pdata.signupKey + '/?r=succeed')})
    except Exception as inst:
        logging.error('Exception when saving participant data : ' + str(inst))

@dajaxice_register(method='POST', name='events.eventSignupDisclaimerJSON')
def eventSignupDisclaimerJSON(request, form):
    postdata = deserialize_form(form)
    
    chck_res = check_signup_captcha(request, postdata)
    if not chck_res.is_valid:
        return simplejson.dumps({'result': 'captch_failed' })
    
    event_id = postdata.get('event_id', None)
        
    destEvent = Event.objects.get(pk=event_id)
    if destEvent is None:
        return simplejson.dumps({'result': 'event_id_not_exist' })
    
    pSignupKey = postdata.get('signupKey', None)
    if pSignupKey is None:
        return simplejson.dumps({'result': 'invalid_signupkey' })
    
    try:
        pdata = Participant.objects.get(signupKey=pSignupKey)
    except (Participant.DoesNotExist, Participant.MultipleObjectsReturned):
        return simplejson.dumps({'result': 'invalid_signupkey' })
    try :
        pdata.delete()
        return simplejson.dumps({'result':'succeed' , 'redirect_to':('/events/'+event_id+'/disclaimer/')})
    except Exception as inst:
        logging.error('Exception when deleting participant data: ' + str(inst))
        
@login_required
@dajaxice_register(method='GET', name='events.importFromUserProfileJSON')
def importFromUserProfileJSON(request):
    user = request.user
    logging.info('user request profile data to fill sign-up fileds, user:{u}'.format(u=user))
    
    if user.is_anonymous() == True:
        logging.warning('user is anonymous')
        return simplejson.dumps({'result':'illegal_user', 'msg':_('Please login or create an account.')})
    
    try:
        pf = user.userprofile
    except UserProfile.DoesNotExist:
        logging.error('user has no profile instance.')
        return simplejson.dumps({'result':'illegal_user_profile', 'msg':_('Oops, some errors happened, we\'re working on it!')})
    
    if pf.modified <= 0:
        logging.warning('user has not modified his profile yet.')
        return simplejson.dumps({'result':'illegal_user_profile', 'msg':_('Please fill your profile first.')})
    
    fields = UserProfile.signupFields()
    rawdata = serializers.serialize('python', [pf], fields=fields)
    
    actual_data = [d['fields'] for d in rawdata]
    
    actual_data[0].update({'email':user.email})
    actual_data[0].update({'result':'success'})
    
    jsonResult = json.dumps(actual_data, cls=DjangoJSONEncoder)
    logging.info('succeed')
    
    return jsonResult[1:-1]
    